#pragma once

#include <vector>
#include <queue>
#include <functional>
#include <pthread.h>
#include "Thread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"

namespace threadpool
{
    const int defaultthreadnum = 5;

    class ThreadData
    {
    public:
        ThreadData(const std::string name)
            : _threadname(name)
        {
        }

    public:
        std::string _threadname;
    };

    template <class T>
    class ThreadPool
    {

    private:
        ThreadPool(int num = defaultthreadnum)
            : _thread_num(num)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);
            for (int i = 0; i < num; i++)
            {
                std::string threadname = "thread - ";
                threadname += std::to_string(i + 1);

                ThreadData td(threadname);
                Thread<ThreadData> t(threadname, std::bind(&ThreadPool<T>::ThreadRun, this, std::placeholders::_1), td);

                _threads.push_back(t);
            }
        }

        ThreadPool(const ThreadPool &t) = delete;
        void operator=(const ThreadPool &t) = delete;

    public:
        static ThreadPool<T> *GetInstance()
        {
            if (instance == nullptr)
            {
                LockGuard lockguard(&sig_lock); // 申请不成功就会阻塞，不能立即返回，所以加双if提升效率
                if (instance == nullptr)
                {
                    instance = new ThreadPool<T>();
                    lg(Info, "单例创建成功。。。。\n");
                }
            }

            return instance;
        }

        // todo
        //  void checkSelf()
        //  {
        //      // lg(Fatal, "进入---");
        //      LockGuard lockguard(&_mutex);
        //      // 扩容
        //      if (_q.size() > _task_num_high_water && _thread_num < _thread_num_high_water)

        //     {
        //         sleep(5);
        //         lg(Fatal, "add thraed");
        //         std::string threadname = "thread - ";
        //         threadname += std::to_string(_threads.size() + 1);

        //         ThreadData td(threadname);
        //         Thread<ThreadData> t(threadname, std::bind(&ThreadPool<T>::ThreadRun, this, std::placeholders::_1), td);
        //         _threads.push_back(t);
        //         t.Start();
        //         _thread_num++;
        //     }
        //     // 缩容
        //     if (_q.size() == _task_num_low_water && _thread_num >= _thread_num_high_water)

        //     {
        //         sleep(10);
        //         lg(Fatal, "-- thraed");
        //         pthread_cancel(_threads[_thread_num - 1].GetId());
        //         _threads.back().Join();
        //         _threads.pop_back();
        //         _thread_num--;
        //     }
        // }

        void Start()
        {
            for (int i = 0; i < _thread_num; i++)
            {
                _threads[i].Start();
                lg(Debug, "thread start thread name : %s \n", _threads[i].ThreadName().c_str());
            }
        }

        void Push(const T &in)
        {
            // checkSelf();
            LockGuard lockguard(&_mutex);
            _q.push(in);
            ThreadWakeUp();
        }

        // 封装一下cond
        void ThreadWait(ThreadData &td)
        {
            pthread_cond_wait(&_cond, &_mutex);
            lg(Debug, "waitthread : %s\n", td._threadname.c_str());
        }

        void ThreadWakeUp()
        {
            pthread_cond_signal(&_cond);
        }

        void ThreadRun(ThreadData &td)
        {
            while (true)
            {
                // std::cout << "runing done ..." << std::endl;
                // sleep(1);
                T t;
                {
                    LockGuard lockguard(&_mutex);
                    while (_q.empty())
                    {
                        ThreadWait(td);
                    }
                    // 一定有任务
                    t = _q.front();
                    _q.pop();
                    // checkSelf();
                }
                t(); // 运行转发方法，将消息转发到所有客服端
                // lg(Info, "Task done : %s   thread name : \n", t.PrintResult().c_str(), td._threadname.c_str());

                // pthread_testcancel(); //设置检查点
                // std::cout << "runing done : " << t.PrintResult() << std::endl;
            }
        }

        void Wait()
        {
            for (int i = 0; i < _thread_num; i++)
            {
                _threads[i].Join();
                lg(Debug, "wait thread thread name : %s \n", _threads[i].ThreadName().c_str());
            }
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

    private:
        std::vector<Thread<ThreadData>> _threads;
        std::queue<T> _q;

        int _thread_num;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;

        static pthread_mutex_t sig_lock; // 单例锁
        static ThreadPool<T> *instance;

        ///////////////////////////////
        int _thread_num_low_water = 5;   // 3
        int _thread_num_high_water = 15; // 10
        int _task_num_low_water = 0;     // 0
        int _task_num_high_water = 30;   // 30
    };

    template <class T>
    ThreadPool<T> *ThreadPool<T>::instance = nullptr;

    template <class T>
    pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;

}